#!/usr/bin/perl

use strict;
use DBI;
use Astro::Time;

# the database handle
my $dbh;

print "Connecting to calibrator database...\n\n";
&start_database_connection;

print "Getting full list of calibrators from database...\n\n";
my @band_array=('16cm','6cm','15mm','7mm','3mm');
my @band_names=('16cm','6/3cm','15mm','7mm','3mm');
my @length_array=('6000','1500','750','375');
my @length_names=('6km','1.5km','750m','375m');
my @region_names=('p','h02','h06','h10','h14','h18','h22',
		  'e01','e03','e05','e07','e09','e11','e13','e15','e17','e19','e21','e23',
		  'z01','z03','z05','z07','z09','z11','z13','z15','z17','z19','z21','z23',
		  'n01','n03','n05','n07','n09','n11','n13','n15','n17','n19','n21','n23');
my @region_seeds=('0637-752','0208-512','0637-752','1004-50','j1326-5256','1613-586','1831-711',
		  '0104-408','0229-398','0537-441','0602-424','0826-373','1039-47','1206-399','1424-418','1600-44','1759-39','2052-474','2326-477',
		  '0118-272','0346-279','0402-362','0745-330','0759-283','1034-293','1313-333','1425-274','1604-333','1921-293','2032-350','2255-282',
		  '0003-066','0215+015','0420-014','0607-157','0906+015','1055+018','1244-255','1548+056','1730-130','1908-201','2145+067','2223-052');
my %calibrator_list = &list_calibrators();
my %selection = ( 'band' => '6cm', 'array' => '6000',
		  'observation' => 'none', # whether there has been an observation of this source
		  'flux' => 'none', 'fluxcriteria' => 'none', 'fluxlevel' => 0,
		  'age' => 'none', 'agecriteria' => 'none', 'agelevel' => 0,
		  'region' => 'none',
		  'defect' => 'none', 'defectcriteria' => 'none', 'defectlevel' => 0
	      );
my @inclusions;
my @exclusions;

my $updated=1;
while ($updated>=0){
    print "Criteria:\n";
    print "    Array: ".$selection{'array'}."\n";
    print "     Band: ".$selection{'band'}."\n";
    print " Observed: ".$selection{'observation'};
    for (my $i=0;$i<=$#inclusions;$i++){
	if ($inclusions[$i]->{'observation'}){
	    print " +".$inclusions[$i]->{'observation'};
	}
    }
    for (my $i=0;$i<=$#exclusions;$i++){
	if ($exclusions[$i]->{'observation'}){
	    print " -".$exclusions[$i]->{'observation'};
	}
    }
    print "\n";
    print "      Age: ";
    if ($selection{'age'} eq 'none'){
	print "any";
    } elsif ($selection{'age'} eq 'yes'){
	print $selection{'agecriteria'}." ".$selection{'agelevel'}." days";
    }
    for (my $i=0;$i<=$#inclusions;$i++){
	if ($inclusions[$i]->{'age'}){
	    if ($inclusions[$i]->{'age'} eq 'none'){
		print " +any";
	    } elsif ($inclusions[$i]->{'age'} eq 'yes'){
		print " +".$inclusions[$i]->{'agecriteria'}." ".
		    $inclusions[$i]->{'agelevel'}." days";
	    }
	}
    }
    for (my $i=0;$i<=$#exclusions;$i++){
	if ($exclusions[$i]->{'age'}){
	    if ($exclusions[$i]->{'age'} eq 'none'){
		print " -any";
	    } elsif ($exclusions[$i]->{'age'} eq 'yes'){
		print " -".$exclusions[$i]->{'agecriteria'}." ".
		    $exclusions[$i]->{'agelevel'}." days";
	    }
	}
    }
    print "\n";
    print "     Flux: ";
    if ($selection{'flux'} eq 'none'){
	print "any";
    } elsif ($selection{'flux'} eq 'no'){
	print "none";
    } elsif ($selection{'flux'} eq 'yes'){
	print $selection{'fluxcriteria'}." ".$selection{'fluxlevel'}." Jy";
    }
    for (my $i=0;$i<=$#inclusions;$i++){
	if ($inclusions[$i]->{'flux'}){
	    if ($inclusions[$i]->{'flux'} eq 'none'){
		print " +any";
	    } elsif ($inclusions[$i]->{'flux'} eq 'no'){
		print " +none";
	    } elsif ($inclusions[$i]->{'flux'} eq 'yes'){
		print " +".$inclusions[$i]->{'fluxcriteria'}." ".
		    $inclusions[$i]->{'fluxlevel'}." Jy";
	    }
	}
    }
    for (my $i=0;$i<=$#exclusions;$i++){
	if ($exclusions[$i]->{'flux'}){
	    if ($exclusions[$i]->{'flux'} eq 'none'){
		print " -any";
	    } elsif ($exclusions[$i]->{'flux'} eq 'no'){
		print " -none";
	    } elsif ($exclusions[$i]->{'flux'} eq 'yes'){
		print " -".$exclusions[$i]->{'fluxcriteria'}." ".
		    $exclusions[$i]->{'fluxlevel'}." Jy";
	    }
	}
    }
    print "\n";
    print "   Region: ";
    if ($selection{'region'} eq 'none'){
	print "any";
    } else {
	print $selection{'region'};
    }
    for (my $i=0;$i<=$#inclusions;$i++){
	if ($inclusions[$i]->{'region'}){
	    if ($inclusions[$i]->{'region'} eq 'none'){
		print " +any";
	    } else {
		print " +".$inclusions[$i]->{'region'};
	    }
	}
    }
    for (my $i=0;$i<=$#exclusions;$i++){
	if ($exclusions[$i]->{'region'}){
	    if ($exclusions[$i]->{'region'} eq 'none'){
		print " -any";
	    } else {
		print " -".$exclusions[$i]->{'region'};
	    }
	}
    }
    print "\n";
    print "   Defect: ";
    if ($selection{'defect'} eq 'none'){
	print "any";
    } elsif ($selection{'defect'} eq 'no'){
	print "none";
    } elsif ($selection{'defect'} eq 'yes'){
	print $selection{'defectcriteria'}." ".$selection{'defectlevel'}." %";
    }
    for (my $i=0;$i<=$#inclusions;$i++){
	if ($inclusions[$i]->{'defect'}){
	    if ($inclusions[$i]->{'defect'} eq 'none'){
		print " +any";
	    } elsif ($inclusions[$i]->{'defect'} eq 'no'){
		print " +none";
	    } elsif ($inclusions[$i]->{'defect'} eq 'yes'){
		print " +".$inclusions[$i]->{'defectcriteria'}." ".
		    $inclusions[$i]->{'defectlevel'}." %";
	    }
	}
    }
    for (my $i=0;$i<=$#exclusions;$i++){
	if ($exclusions[$i]->{'defect'}){
	    if ($exclusions[$i]->{'defect'} eq 'none'){
		print " +any";
	    } elsif ($exclusions[$i]->{'defect'} eq 'no'){
		print " +none";
	    } elsif ($exclusions[$i]->{'defect'} eq 'yes'){
		print " +".$exclusions[$i]->{'defectcriteria'}." ".
		    $exclusions[$i]->{'defectlevel'}." %";
	    }
	}
    }
    print "\n";
    if ($updated==1){
	my $selected_count=&get_selected_count(\%calibrator_list);
	print "Currently selected: ".$selected_count." sources.\n\n";
	$updated=0;
    }

    $updated=&menu();
}

exit;

sub menu {
    print " > ";
    my $inputline;
    chomp($inputline=<STDIN>);

    $inputline=~s/^\s*//g;

    if ($inputline=~/^list(.*)/) {
	# make a list of the sources
	my $arguments=$1;
	my $sourcename='';
	my $maybe_selected=0;
	if ($arguments=~/^\s*all/){
	    # don't care if they're selected or not
	    $maybe_selected=1;
	} elsif ($arguments=~/^\s*([^\s]+)/){
	    $maybe_selected=2;
	    $sourcename=$1;
	}
	&list_sources($maybe_selected,$sourcename,\%calibrator_list,\%selection);
	return 1;
    } elsif (($inputline=~/^quit/)||($inputline=~/^exit/)){
	return -1;
    } elsif ($inputline=~/^select(.*)/) {
	my $arguments=$1;
	$arguments=~s/^\s*//g;
	&line_action($arguments,\%selection);
	&execute_all(\%calibrator_list,\%selection,\@inclusions,
		     \@exclusions);
	return 1;
    } elsif ($inputline=~/^include(.*)/) {
	my $arguments=$1;
	$arguments=~s/^\s*//g;
	&include_exclude_actions("include",$arguments,\%selection,
				 \@inclusions,\@exclusions);
	&execute_all(\%calibrator_list,\%selection,\@inclusions,
		     \@exclusions);
	return 1;
    } elsif ($inputline=~/^exclude(.*)/) {
	my $arguments=$1;
	$arguments=~s/^\s*//g;
	&include_exclude_actions("exclude",$arguments,\%selection,
				 \@inclusions,\@exclusions);
	&execute_all(\%calibrator_list,\%selection,\@inclusions,
		     \@exclusions);
	return 1;
    } elsif ($inputline=~/^make mosaics/){
	&make_mosaics(\%calibrator_list);
    }
}

sub make_mosaics {
    my ($calhashref)=@_;

    for (my $i=0;$i<=$#region_names;$i++){
	# open each file with the seed source
	open(REGOUT,">new_".$region_names[$i].".list");
	if (($region_seeds[$i])&&($region_seeds[$i] ne '')){
	    foreach my $source ( keys %{$calhashref} ) {
		if ($source eq $region_seeds[$i]){
		    print REGOUT $source." ".
			$calhashref->{$source}->{'ra'}." ".
			$calhashref->{$source}->{'dec'}."\n";
		    last;
		}
	    }
	}
	foreach my $source ( keys %{$calhashref} ) {
	    if ($calhashref->{$source}->{'selected'}==0){
		next;
	    }
	    if (($region_seeds[$i])&&($region_seeds[$i] eq $source)){
		next;
	    }
	    my $thisregion=&region($calhashref->{$source}->{'ra'},
				   $calhashref->{$source}->{'dec'});
	    if ($thisregion eq $region_names[$i]){
		print REGOUT $source." ".
		    $calhashref->{$source}->{'ra'}." ".
		    $calhashref->{$source}->{'dec'}."\n";
	    }
	}
	close(REGOUT);
	my $start_lst=$region_names[$i];
	if ($start_lst eq "p") {
	    $start_lst = "00:00:00";
	} else {
	    $start_lst =~ s/^.//;
	    $start_lst .= ":00:00";
	}
	# run atmos now
	my $atmos_command="atmos source=new_".$region_names[$i].".list ".
	    "out=new_".$region_names[$i].".mos cycles=6 lst=".$start_lst;
	system $atmos_command;
    }

}

sub include_exclude_actions {
    my ($action,$argumentline,$selhashref,$inclarrayref,$exclarrayref)=@_;

    my %newselection;
    &line_action($argumentline,\%newselection);
    
    # check if we're cancelling something
    my $cancelled=0;
    if ($action eq "include"){
	for (my $i=0;$i<=$#{$exclarrayref};$i++){
	    my $comp=&comparehash(\%newselection,${$exclarrayref}[$i]);
	    if ($comp==0){
		splice @{$exclarrayref},$i,1;
		$i--;
		$cancelled=1;
	    }
	}
    } elsif ($action eq "exclude"){
	for (my $i=0;$i<=$#{$inclarrayref};$i++){
	    my $comp=&comparehash(\%newselection,${$inclarrayref}[$i]);
	    if ($comp==0){
		splice @{$inclarrayref},$i,1;
		$i--;
		$cancelled=1;
	    }
	}
    }
    if ($cancelled==0){
	if ($action eq "include"){
	    push @{$inclarrayref},\%newselection;
	} elsif ($action eq "exclude"){
	    push @{$exclarrayref},\%newselection;
	}
    }
	
}

sub comparehash {
    my ($hashref1,$hashref2)=@_;

    my $diff=0;
    foreach my $check ( keys %{$hashref1} ) {
	if ($hashref2->{$check}){
	    if ($hashref1->{$check} ne $hashref2->{$check}){
		$diff=1;
		last;
	    }
	} else {
	    $diff=1;
	}
    }

    return $diff;
}

sub line_action {
    my ($argumentline,$selhashref)=@_;

    if ($argumentline=~/observed/){
	if ($argumentline=~/not\s+observed/){
	    $selhashref->{'observation'}='no';
	} elsif ($argumentline=~/either\s+observed/){
	    $selhashref->{'observation'}='none';
	} else {
	    $selhashref->{'observation'}='yes';
	}
    }
    if ($argumentline=~/array\s+([^\s]+)/){
	my $arrayspec=$1;
	my $notfound=1;
	for (my $i=0;$i<=$#length_array;$i++){
	    if (($arrayspec eq $length_array[$i])||
		($arrayspec eq $length_names[$i])){
		$selhashref->{'array'}=$length_array[$i];
		$notfound=0;
		last;
	    }
	}
	if ($notfound==1){
	    print "  valid array choices are:\n";
	    for (my $i=0;$i<=$#length_array;$i++){
		print "   ".$length_array[$i]."   ".$length_names[$i]."\n";
	    }
	}
    }
    if ($argumentline=~/band\s+([^\s]+)/){
	my $bandspec=$1;
	my $notfound=1;
	for (my $i=0;$i<=$#band_array;$i++){
	    if (($bandspec eq $band_array[$i])||
		($bandspec eq $band_names[$i])){
		$selhashref->{'band'}=$band_array[$i];
		$notfound=0;
		last;
	    }
	}
	if ($notfound==1){
	    print "  valid band choices are:\n";
	    for (my $i=0;$i<=$#band_array;$i++){
		print "   ".$band_array[$i]."   ".$band_names[$i]."\n";
	    }
	}
    }
    if ($argumentline=~/age/){
	if ($argumentline=~/any\s+age/){
	    $selhashref->{'age'}='none';
	} elsif ($argumentline=~/age\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)/){
	    my $criteria=$1;
	    my $value=$2;
	    my $units=$3;
	    if (($criteria ne '<')&&($criteria ne '<=')&&
		($criteria ne '>')&&($criteria ne '>=')&&
		($criteria ne '=')){
		print "  usage for age:\n";
		print "   age {<,<=,>,>=,=} N {days,months,years}\n";
		print "    where N is a (possibly decimal) number\n";
		print "   or\n";
		print "   any age\n";
		print "    to disable this constraint\n";
	    } else {
		if (($units ne 'days')&&($units ne 'months')&&
		    ($units ne 'years')){
		    print "  usage for age:\n";
		    print "   age {<,<=,>,>=,=} N {days,months,years}\n";
		    print "    where N is a (possibly decimal) number\n";
		    print "   or\n";
		    print "   any age\n";
		    print "    to disable this constraint\n";
		} else {
		    $selhashref->{'age'}='yes';
		    $selhashref->{'agecriteria'}=$criteria;
		    if ($units eq "days"){
			$selhashref->{'agelevel'}=$value;
		    } elsif ($units eq "months"){
			$selhashref->{'agelevel'}=$value*30;
		    } elsif ($units eq "years"){
			$selhashref->{'agelevel'}=$value*365;
		    }
		}
	    }
	} else {
	    print "  usage for age:\n";
	    print "   age {<,<=,>,>=,=} N {days,months,years}\n";
	    print "    where N is a (possibly decimal) number\n";
	    print "   or\n";
	    print "   any age\n";
	    print "    to disable this constraint\n";
	}
    }
    if ($argumentline=~/flux/){
	if ($argumentline=~/any\s+flux/){
	    $selhashref->{'flux'}='none';
	} elsif ($argumentline=~/flux\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)/){
	    my $criteria=$1;
	    my $value=$2;
	    my $units=$3;
	    if (($criteria ne '<')&&($criteria ne '<=')&&
		($criteria ne '>')&&($criteria ne '>=')&&
		($criteria ne '=')){
		print "  usage for flux:\n";
		print "   flux {<,<=,>,>=,=} N {Jy,mJy}\n";
		print "    where N is a decimal number\n";
		print "   or\n";
		print "   any flux\n";
		print "    to disable this constraint\n";
		print "   or\n";
		print "   no flux\n";
		print "    to select sources that have a flux of 'N/A'\n";
	    } else {
		if (($units ne 'mJy')&&($units ne 'Jy')){
		    print "  usage for flux:\n";
		    print "   flux {<,<=,>,>=,=} N {Jy,mJy}\n";
		    print "    where N is a decimal number\n";
		    print "   or\n";
		    print "   any flux\n";
		    print "    to disable this constraint\n";
		    print "   or\n";
		    print "   no flux\n";
		    print "    to select sources that have a flux of 'N/A'\n";
		} else {
		    $selhashref->{'flux'}='yes';
		    $selhashref->{'fluxcriteria'}=$criteria;
		    if ($units eq "mJy"){
			$selhashref->{'fluxlevel'}=$value/1000;
		    } elsif ($units eq "Jy"){
			$selhashref->{'fluxlevel'}=$value;
		    }
		}
	    }
	} elsif ($argumentline=~/no\s+flux/){
	    $selhashref->{'flux'}='no';
	} else {
	    print "  usage for flux:\n";
	    print "   flux {<,<=,>,>=,=} N {Jy,mJy}\n";
	    print "    where N is a decimal number\n";
	    print "   or\n";
	    print "   any flux\n";
	    print "    to disable this constraint\n";
	    print "   or\n";
	    print "   no flux\n";
	    print "    to select sources that have a flux of 'N/A'\n";
	}
    } elsif ($argumentline=~/region/){
	if ($argumentline=~/any\s+region/){
	    $selhashref->{'region'}='none';
	} elsif ($argumentline=~/region\s+([^\s]+)/){
	    my $regionarg=$1;
	    my $regionfound=0;
	    for (my $i=0;$i<=$#region_names;$i++){
		if ($regionarg eq $region_names[$i]){
		    $selhashref->{'region'}=$regionarg;
		    $regionfound=1;
		    last;
		}
	    }
	    if ($regionfound==0){
		print "  unrecognised region, possible regions are:\n";
		print "  ";
		for (my $i=0;$i<=$#region_names;$i++){
		    print " ".$region_names[$i];
		}
		print "\n";
	    }
	} else {
	    print "  usage for region:\n";
	    print "   region NAME\n";
	    print "    where NAME is the C007 region name\n";
	    print "   or\n";
	    print "   any region\n";
	    print "    to disable this constraint\n";
	}
    } elsif ($argumentline=~/defect/){
	if ($argumentline=~/any\s+defect/){
	    $selhashref->{'defect'}='none';
	} elsif ($argumentline=~/defect\s+([^\s]+)\s+([^\s]+)/){
	    my $criteria=$1;
	    my $value=$2;
	    if (($criteria ne '<')&&($criteria ne '<=')&&
		($criteria ne '>')&&($criteria ne '>=')&&
		($criteria ne '=')){
		print "  usage for defect:\n";
		print "   defect {<,<=,>,>=,=} N\n";
		print "    where N is a decimal number\n";
		print "   or\n";
		print "   any defect\n";
		print "    to disable this constraint\n";
		print "   or\n";
		print "   no defect\n";
		print "    to select sources that have a defect of 'N/A'\n";
	    } else {
		$selhashref->{'defect'}='yes';
		$selhashref->{'defectcriteria'}=$criteria;
		$selhashref->{'defectlevel'}=$value;
	    }
	} elsif ($argumentline=~/no\s+defect/){
	    $selhashref->{'defect'}='no';
	} else {
	    print "  usage for defect:\n";
	    print "   defect {<,<=,>,>=,=} N\n";
	    print "    where N is a decimal number\n";
	    print "   or\n";
	    print "   any defect\n";
	    print "    to disable this constraint\n";
	    print "   or\n";
	    print "   no defect\n";
	    print "    to select sources that have a defect of 'N/A'\n";
	}
    }
}

sub execute_all {
    my ($calhashref,$selhashref,$inclarrayref,$exclarrayref)=@_;

    &execute_selection("select",$calhashref,$selhashref);
    for (my $i=0;$i<=$#{$inclarrayref};$i++){
	&execute_selection("include",$calhashref,${$inclarrayref}[$i],$selhashref);
    }
    for (my $i=0;$i<=$#{$exclarrayref};$i++){
	&execute_selection("exclude",$calhashref,${$exclarrayref}[$i],$selhashref);
    }
}

sub execute_selection {
    my $mode=shift;
    my $calhashref=shift;
    my $selhashref=shift;
    my $secselhashref=shift;

    foreach my $source ( keys %{$calhashref} ) {
	if ($mode eq "select"){
	    $calhashref->{$source}->{'selected'}=1;
	} elsif (($mode eq "include")&&($calhashref->{$source}->{'selected'}==1)){
	    next;
	} elsif (($mode eq "exclude")&&($calhashref->{$source}->{'selected'}==0)){
	    next;
	}
	if ($selhashref->{'observation'}){
	    if ($selhashref->{'observation'} eq 'no') {
		if (($mode eq "select")&&
		    ($calhashref->{$source}->{'times'}->{$selhashref->{'band'}}->{$selhashref->{'array'}}
		     ne "too long")){
		    $calhashref->{$source}->{'selected'}=0;
		    next;
		} elsif (($mode eq "include")&&
			 ($calhashref->{$source}->{'times'}->{$secselhashref->{'band'}}->{$secselhashref->{'array'}}
			  eq "too long")){
		    $calhashref->{$source}->{'selected'}=1;
		    next;
		} elsif (($mode eq "exclude")&&
			 ($calhashref->{$source}->{'times'}->{$secselhashref->{'band'}}->{$secselhashref->{'array'}}
			  eq "too long")){
		    $calhashref->{$source}->{'selected'}=0;
		    next;
		}
	    }
	    if ($selhashref->{'observation'} eq 'yes'){
		if (($mode eq "select")&&
		    ($calhashref->{$source}->{'times'}->{$selhashref->{'band'}}->{$selhashref->{'array'}}
		     eq "too long")){
		    $calhashref->{$source}->{'selected'}=0;
		    next;
		} elsif (($mode eq "include")&&
			 ($calhashref->{$source}->{'times'}->{$secselhashref->{'band'}}->{$secselhashref->{'array'}}
			  ne "too long")){
		    $calhashref->{$source}->{'selected'}=1;
		    next;
		} elsif (($mode eq "exclude")&&
			 ($calhashref->{$source}->{'times'}->{$secselhashref->{'band'}}->{$secselhashref->{'array'}}
			  ne "too long")){
		    $calhashref->{$source}->{'selected'}=0;
		    next;
		}
	    }
	}
	if ($selhashref->{'age'}){
	    my $thisage;
	    if ($mode eq "select"){
		$thisage=&age($calhashref->{$source}->{'times'}->{$selhashref->{'band'}}->{$selhashref->{'array'}});
	    } elsif (($mode eq "include")||($mode eq "exclude")){
		$thisage=&age($calhashref->{$source}->{'times'}->{$secselhashref->{'band'}}->{$secselhashref->{'array'}});
	    }
	    if ($selhashref->{'age'} eq 'yes'){
		if (($mode eq "select")&&($selhashref->{'observation'} eq 'yes')){
		    if ((($selhashref->{'agecriteria'} eq '>')&&($thisage<=$selhashref->{'agelevel'}))||
			(($selhashref->{'agecriteria'} eq '>=')&&($thisage<$selhashref->{'agelevel'}))||
			(($selhashref->{'agecriteria'} eq '<')&&($thisage>=$selhashref->{'agelevel'}))||
			(($selhashref->{'agecriteria'} eq '<=')&&($thisage>$selhashref->{'agelevel'}))||
			(($selhashref->{'agecriteria'} eq '=')&&($thisage!=$selhashref->{'agelevel'}))){
			$calhashref->{$source}->{'selected'}=0;
		    }
		} elsif ($mode eq "include"){
		    if ((($selhashref->{'agecriteria'} eq '>')&&($thisage>$selhashref->{'agelevel'}))||
			(($selhashref->{'agecriteria'} eq '>=')&&($thisage>=$selhashref->{'agelevel'}))||
			(($selhashref->{'agecriteria'} eq '<')&&($thisage<$selhashref->{'agelevel'}))||
			(($selhashref->{'agecriteria'} eq '<=')&&($thisage<=$selhashref->{'agelevel'}))||
			(($selhashref->{'agecriteria'} eq '=')&&($thisage==$selhashref->{'agelevel'}))){
			$calhashref->{$source}->{'selected'}=1;
		    }
		} elsif ($mode eq "exclude"){
		    if ((($selhashref->{'agecriteria'} eq '>')&&($thisage>$selhashref->{'agelevel'}))||
			(($selhashref->{'agecriteria'} eq '>=')&&($thisage>=$selhashref->{'agelevel'}))||
			(($selhashref->{'agecriteria'} eq '<')&&($thisage<$selhashref->{'agelevel'}))||
			(($selhashref->{'agecriteria'} eq '<=')&&($thisage<=$selhashref->{'agelevel'}))||
			(($selhashref->{'agecriteria'} eq '=')&&($thisage==$selhashref->{'agelevel'}))){
			$calhashref->{$source}->{'selected'}=0;
		    }
		}
	    }
	}
	if ($selhashref->{'flux'}){
	    my $thisflux;
	    if ($mode eq "select"){
		$thisflux=$calhashref->{$source}->{'fluxes'}->{$selhashref->{'band'}};
	    } elsif (($mode eq "include")||($mode eq "exclude")){
		$thisflux=$calhashref->{$source}->{'fluxes'}->{$secselhashref->{'band'}};
	    }
	    if ($selhashref->{'flux'} eq 'yes'){
		if (($mode eq "select")&&($thisflux < 0)){
		    $calhashref->{$source}->{'selected'}=0;
		} elsif ($mode eq "select") {
		    if ((($selhashref->{'fluxcriteria'} eq '>')&&($thisflux<=$selhashref->{'fluxlevel'}))||
			(($selhashref->{'fluxcriteria'} eq '>=')&&($thisflux<$selhashref->{'fluxlevel'}))||
			(($selhashref->{'fluxcriteria'} eq '<')&&($thisflux>=$selhashref->{'fluxlevel'}))||
			(($selhashref->{'fluxcriteria'} eq '<=')&&($thisflux>$selhashref->{'fluxlevel'}))||
			(($selhashref->{'fluxcriteria'} eq '=')&&($thisflux!=$selhashref->{'fluxlevel'}))){
			$calhashref->{$source}->{'selected'}=0;
		    }
		} elsif ($mode eq "include") {
		    if ((($selhashref->{'fluxcriteria'} eq '>')&&($thisflux>$selhashref->{'fluxlevel'}))||
			(($selhashref->{'fluxcriteria'} eq '>=')&&($thisflux>=$selhashref->{'fluxlevel'}))||
			(($selhashref->{'fluxcriteria'} eq '<')&&($thisflux<$selhashref->{'fluxlevel'}))||
			(($selhashref->{'fluxcriteria'} eq '<=')&&($thisflux<=$selhashref->{'fluxlevel'}))||
			(($selhashref->{'fluxcriteria'} eq '=')&&($thisflux==$selhashref->{'fluxlevel'}))){
			$calhashref->{$source}->{'selected'}=1;
		    }
		} elsif ($mode eq "exclude"){
		    if ((($selhashref->{'fluxcriteria'} eq '>')&&($thisflux>$selhashref->{'fluxlevel'}))||
			(($selhashref->{'fluxcriteria'} eq '>=')&&($thisflux>=$selhashref->{'fluxlevel'}))||
			(($selhashref->{'fluxcriteria'} eq '<')&&($thisflux<$selhashref->{'fluxlevel'}))||
			(($selhashref->{'fluxcriteria'} eq '<=')&&($thisflux<=$selhashref->{'fluxlevel'}))||
			(($selhashref->{'fluxcriteria'} eq '=')&&($thisflux==$selhashref->{'fluxlevel'}))){
			$calhashref->{$source}->{'selected'}=0;
		    }
		}
	    } elsif ($selhashref->{'flux'} eq 'no'){
		my $thisflux;
		if ($mode eq "select"){
		    $thisflux=$calhashref->{$source}->{'fluxes'}->{$selhashref->{'band'}};
		} elsif (($mode eq "include")||($mode eq "exclude")){
		    $thisflux=$calhashref->{$source}->{'fluxes'}->{$secselhashref->{'band'}};
		}
		if (($mode eq "select")&&($thisflux > 0)){
		    $calhashref->{$source}->{'selected'}=0;
		} elsif (($mode eq "include")&&($thisflux < 0)){
		    $calhashref->{$source}->{'selected'}=1;
		} elsif (($mode eq "exclude")&&($thisflux < 0)){
		    $calhashref->{$source}->{'selected'}=0;
		}
	    }
	}
	if ($selhashref->{'region'}){
	    if ($selhashref->{'region'} ne 'none'){
		my $thisregion=&region($calhashref->{$source}->{'ra'},
				       $calhashref->{$source}->{'dec'});
		if (($mode eq "select")&&($thisregion ne $selhashref->{'region'})){
		    $calhashref->{$source}->{'selected'}=0;
		} elsif (($mode eq "include")&&($thisregion eq $selhashref->{'region'})){
		    $calhashref->{$source}->{'selected'}=1;
		} elsif (($mode eq "exclude")&&($thisregion eq $selhashref->{'region'})){
		    $calhashref->{$source}->{'selected'}=0;
		}
	    }
	}
	if ($selhashref->{'defect'}){
	    if ($selhashref->{'defect'} eq 'yes'){
		my $thisdefect;
		if ($mode eq "select"){
		    $thisdefect=$calhashref->{$source}->{'defects'}->{$selhashref->{'band'}}->{$selhashref->{'array'}};
		} elsif (($mode eq "include")||($mode eq "exclude")){
		    $thisdefect=$calhashref->{$source}->{'defects'}->{$secselhashref->{'band'}}->{$secselhashref->{'array'}};
		}
		if (($mode eq "select")&&($thisdefect<0)){
		    $calhashref->{$source}->{'selected'}=0;
		} else {
		    if (($mode eq "select")&&
			((($selhashref->{'defectcriteria'} eq '>')&&($thisdefect<=$selhashref->{'defectlevel'}))||
			 (($selhashref->{'defectcriteria'} eq '>=')&&($thisdefect<$selhashref->{'defectlevel'}))||
			 (($selhashref->{'defectcriteria'} eq '<')&&($thisdefect>=$selhashref->{'defectlevel'}))||
			 (($selhashref->{'defectcriteria'} eq '<=')&&($thisdefect>$selhashref->{'defectlevel'}))||
			 (($selhashref->{'defectcriteria'} eq '=')&&($thisdefect!=$selhashref->{'defectlevel'})))){
			$calhashref->{$source}->{'selected'}=0;
		    } elsif (($mode eq "include")&&
			     ((($selhashref->{'defectcriteria'} eq '>')&&($thisdefect>$selhashref->{'defectlevel'}))||
			      (($selhashref->{'defectcriteria'} eq '>=')&&($thisdefect>=$selhashref->{'defectlevel'}))||
			      (($selhashref->{'defectcriteria'} eq '<')&&($thisdefect<$selhashref->{'defectlevel'}))||
			      (($selhashref->{'defectcriteria'} eq '<=')&&($thisdefect<=$selhashref->{'defectlevel'}))||
			      (($selhashref->{'defectcriteria'} eq '=')&&($thisdefect==$selhashref->{'defectlevel'})))){
			$calhashref->{$source}->{'selected'}=1;
		    } elsif (($mode eq "exclude")&&
			     ((($selhashref->{'defectcriteria'} eq '>')&&($thisdefect>$selhashref->{'defectlevel'}))||
			      (($selhashref->{'defectcriteria'} eq '>=')&&($thisdefect>=$selhashref->{'defectlevel'}))||
			      (($selhashref->{'defectcriteria'} eq '<')&&($thisdefect<$selhashref->{'defectlevel'}))||
			      (($selhashref->{'defectcriteria'} eq '<=')&&($thisdefect<=$selhashref->{'defectlevel'}))||
			      (($selhashref->{'defectcriteria'} eq '=')&&($thisdefect==$selhashref->{'defectlevel'})))){
			$calhashref->{$source}->{'selected'}=0;
		    }
		}
	    } elsif ($selhashref->{'defect'} eq 'no'){
		my $thisdefect;
		if ($mode eq "select"){
		    $thisdefect=$calhashref->{$source}->{'defects'}->{$selhashref->{'band'}}->{$selhashref->{'array'}};
		} elsif (($mode eq "include")||($mode eq "exclude")){
		    $thisdefect=$calhashref->{$source}->{'defects'}->{$secselhashref->{'band'}}->{$secselhashref->{'array'}};
		}
		if (($mode eq "select")&&($thisdefect>0)){
		    $calhashref->{$source}->{'selected'}=0;
		} elsif (($mode eq "include")&&($thisdefect<0)){
		    $calhashref->{$source}->{'selected'}=1;
		} elsif (($mode eq "exclude")&&($thisdefect<0)){
		    $calhashref->{$source}->{'selected'}=0;
		}
	    }
	}
    }
}

sub perltime2mjd {
    # perl time should be (second,minute,hour,day,month-1,year-1900)
    my @fulltime=@_;
    
    my $ut=hms2time($fulltime[2],$fulltime[1],$fulltime[0]);
    my $mjd=cal2mjd($fulltime[3],$fulltime[4]+1,$fulltime[5]+1900,$ut);

    return $mjd;
}    

sub region {
    my ($ra,$dec)=@_;

    my $rad=&sexa2decimal($ra);
    my $decd=&sexa2decimal($dec);

    if ($decd<=-74){
	return "p"; # polar region
    } elsif ($decd<=-49){
	# the "h" region
	if ($rad<=4){
	    return "h02";
	} elsif ($rad<=8){
	    return "h06";
	} elsif ($rad<=12){
	    return "h10";
	} elsif ($rad<=16){
	    return "h14";
	} elsif ($rad<=20){
	    return "h18";
	} else {
	    return "h22";
	}
    } else {
	# the rest of the sky is broken into 2 hour chunks
	my $prefix="";
	if ($decd<=-37){
	    $prefix="e";
	} elsif ($decd<=-27){
	    $prefix="z";
	} elsif ($decd<=10) {
	    $prefix="n";
	}
	if ($rad<=2){
	    return $prefix."01";
	} elsif ($rad<=4){
	    return $prefix."03";
	} elsif ($rad<=6){
	    return $prefix."05";
	} elsif ($rad<=8){
	    return $prefix."07";
	} elsif ($rad<=10){
	    return $prefix."09";
	} elsif ($rad<=12){
	    return $prefix."11";
	} elsif ($rad<=14){
	    return $prefix."13";
	} elsif ($rad<=16){
	    return $prefix."15";
	} elsif ($rad<=18){
	    return $prefix."17";
	} elsif ($rad<=20){
	    return $prefix."19";
	} elsif ($rad<=22){
	    return $prefix."21";
	} else {
	    return $prefix."23";
	}
    }
}

sub sexa2decimal {
    my ($sexavalue)=@_;

    my @els=split(/[\s\:]+/,$sexavalue);
    
    my $decivalue = $els[0];
    my $sign=1;
    if ($sexavalue=~/^\-/){
	$sign=-1;
    }
    $decivalue*=$sign;
    $decivalue+=$els[1]/60;
    $decivalue+=$els[2]/3600;
    $decivalue*=$sign;

    return $decivalue;
}

sub age {
    my ($lasttime)=@_;
    my $thisage=0;

    if ($lasttime=~/(\d\d\d\d)\-(\d\d)\-(\d\d)\s(\d\d)\:(\d\d)\:(\d\d)/){
	my @spectime=($6,$5,$4,$3,$2-1,$1-1900);
	my $specmjd=&perltime2mjd(@spectime);
	# get the time now
	my @currenttime=gmtime(time);
	my $currentmjd=&perltime2mjd(@currenttime);
	$thisage=$currentmjd-$specmjd;
    }
    
    return $thisage;
}

sub list_sources {
    my ($all,$sourcename,$calhashref,$selhashref)=@_;

    my $title_lineformat="%-16.16s  %-11.11s  %-11.11s  %9.9s  %-20.20s  %6.6s\n";
    printf $title_lineformat,"Source","RA","Dec","Flux (Jy)","Last observed","Defect";
    printf $title_lineformat,"----------------","-----------","-----------","---------",
    "--------------------","------";
    foreach my $source ( keys %{$calhashref} ) {
	if ((($all==2)&&($source eq $sourcename))||
	    (($all==0)&&($calhashref->{$source}->{'selected'}==1))||
	    ($all==1)){
	    my $fluxstring=
		&flux_to_string($calhashref->{$source}->{'fluxes'}->{$selhashref->{'band'}});
	    my $defectstring=
		&defect_to_string($calhashref->{$source}->{'defects'}->{$selhashref->{'band'}}->{$selhashref->{'array'}});
	    printf $title_lineformat,$source,$calhashref->{$source}->{'ra'},
	    $calhashref->{$source}->{'dec'},$fluxstring,
	    $calhashref->{$source}->{'times'}->{$selhashref->{'band'}}->{$selhashref->{'array'}},
	    $defectstring;
	}
    }
}

sub defect_to_string {
    my ($defect)=@_;

    if ($defect<0){
	return "N/A";
    } else {
	return sprintf "%6.2f",$defect;
    }
}

sub flux_to_string {
    my ($flux)=@_;

    if ($flux<0){
	return "N/A";
    } else {
	return sprintf "%9.3f",$flux;
    }
}

sub get_selected_count {
    my ($calhashref)=@_;

    my $selected_count=0;
    foreach my $source ( keys %{$calhashref} ) {
	if ($calhashref->{$source}->{'selected'}==1) {
	    $selected_count++;
	}
    }

    return $selected_count;
}

sub list_calibrators {

    # get a list of all the calibrators
    my $all_calibrators_query="SELECT name,ra,dec FROM calibrators WHERE ".
	"dec_to_decimal(dec)<=10 AND catalogue!='' ORDER BY name";
    my $all_calibrators_handle=$dbh->prepare($all_calibrators_query);
    $all_calibrators_handle->execute;
    my %calibrators;
    while (my ($calname,$calra,$caldec)=$all_calibrators_handle->fetchrow()){
	my %times_hash;
	my %epochs_hash;
	my %fluxes_hash;
	my %defects_hash;
	for (my $i=0;$i<=$#band_array;$i++){
	    $epochs_hash{$band_array[$i]}='';
	    $fluxes_hash{$band_array[$i]}=-99;
	    for (my $j=0;$j<=$#length_array;$j++){
		$times_hash{$band_array[$i]}->{$length_array[$j]}="too long";
		$defects_hash{$band_array[$i]}->{$length_array[$j]}=-99;
	    }
	}
	$calibrators{$calname} = { 'ra' => $calra, 'dec' => $caldec,
				   'times' => \%times_hash,
				   'epochs' => \%epochs_hash,
				   'fluxes' => \%fluxes_hash,
				   'defects' => \%defects_hash,
				   'selected' => 1 };
    }
    $all_calibrators_handle->finish;
    
    # search for the latest times
    my $times_query="SELECT max(time) AS \"latest observation\",observation.source,".
	"baseline_length_classify(arrayname) AS baselength,".
	"wavelength_band(if_freq[1]) AS band,avg(fluxdata.closurephase_measured[1]) ".
	"FROM observation INNER JOIN calibrators ON ".
	"(observation.source=calibrators.name) INNER JOIN fluxdata ON ".
	"(observation.id=ANY(fluxdata.observation_ids)) WHERE ".
	"project_code='C007' AND arrayname!='' AND if_freq!='{}' ".
	"GROUP BY observation.source,baselength,band ".
	"ORDER BY observation.source";
    my $times_handle=$dbh->prepare($times_query);
    $times_handle->execute;
    while (my ($lasttime,$sourcename,$baselength,$bandname,$defect)=
	   $times_handle->fetchrow()){
	if ($calibrators{$sourcename}){
	    $calibrators{$sourcename}->{'times'}->{$bandname}->{$baselength}=$lasttime;
	    $calibrators{$sourcename}->{'defects'}->{$bandname}->{$baselength}=$defect;
	}
    }
    $times_handle->finish;

    # search for the latest fluxes
    my $fluxes_query="SELECT fluxdata.source,date_trunc('day',observation.time) AS ".
	"epoch,avg(fluxdata.tripleamp_value[1]),wavelength_band(fluxdata.frequency) ".
	"AS band FROM fluxdata INNER JOIN observation ON (observation.id=".
	"ANY(fluxdata.observation_ids)) INNER JOIN calibrators ON (calibrators.name=".
	"fluxdata.source) WHERE fluxdata.reduced_auto=FALSE AND ".
	"fluxdata.tripleamp_value[1]>0 GROUP BY fluxdata.source,band,epoch ".
	"ORDER BY source,epoch DESC";
    my $fluxes_handle=$dbh->prepare($fluxes_query);
    $fluxes_handle->execute;
    while (my ($sourcename,$epoch,$fluxdensity,$bandname,$defect)=$fluxes_handle->fetchrow()){
	if ($calibrators{$sourcename}){
	    if ($calibrators{$sourcename}->{'epochs'}->{$bandname} eq ''){
		$calibrators{$sourcename}->{'epochs'}->{$bandname}=$epoch;
		$calibrators{$sourcename}->{'fluxes'}->{$bandname}=$fluxdensity;
	    }
	}
    }
    $fluxes_handle->finish;

    return %calibrators;
}


sub start_database_connection {
    my $database = shift;

    # open a connection to the ATCA calibrator database
    my $dsn="dbi:Pg:dbname=atca;host=mentok;port=5432";
    my $db_user="postgres";
    my $db_password="postgres";
    $dbh=DBI->connect($dsn,$db_user,$db_password,
		      {RaiseError => 0, AutoCommit => 1,
		       PrintError => 1});

}
